<!--
 * @Author: pmy
 * @Date: 2021-09-02 14:39:12
 * @LastEditTime: 2022-11-25 09:57:21
 * @LastEditors: pmy
 * @Description: 产品结构与折扣-table
 * @FilePath: \bdcar-net\src\components\table\baseTable.vue
-->
<template>
  <div class="tablePage" v-loading="loading">
    <div class="search">
      <div class="header-query" v-for="v in queryInput" :key="v.prop">
        <span class="search-text">{{ v.name }}</span>
        <el-input clearable v-model="v.value" :placeholder="v.placeholder" class="search-input"
          @keyup.native.enter="getTableData()"></el-input>
      </div>
      <div class="header-query" v-for="v in querySelect" :key="v.prop">
        <span class="search-text">{{ v.name }}</span>
        <el-select v-model="v.value" :placeholder="v.placeholder" filterable class="search-input"
          @change="getTableData()">
          <el-option v-for="vv in optionList[v.prop]" :key="vv.value" :label="vv.label" :value="vv.value"> </el-option>
        </el-select>
      </div>
      <div class="header-query" v-for="v in queryCascader" :key="v.prop">
        <span class="search-text">{{ v.name }}</span>
        <el-cascader v-model="v.value" class="search-input" :placeholder="v.placeholder" :options="optionList[v.prop]"
          :props="cascaderSet" @change="getTableData()" :clearable="false"></el-cascader>
      </div>
      <div class="header-query" v-for="v in queryTime" :key="v.prop">
        <span class="search-text">{{ v.name }}</span>
        <el-date-picker v-model="v.value" type="daterange" range-separator="至" :start-placeholder="v.placeholder[0]"
          :clearable="false" :end-placeholder="v.placeholder[1]" :picker-options="pickerOptions"
          class="search-input time-picker" format="yyyy-MM-dd" value-format="yyyy-MM-dd">
        </el-date-picker>
      </div>
      <div class="header-query" v-for="v in queryMonth" :key="v.prop">
        <span class="search-text">{{ v.name }}</span>
        <el-date-picker v-model="v.value" type="monthrange" range-separator="至" :start-placeholder="v.placeholder[0]"
          :clearable="false" :end-placeholder="v.placeholder[1]" :picker-options="pickerOptionsMonth"
          class="search-input time-picker" format="yyyy-MM" value-format="yyyy-MM">
        </el-date-picker>
      </div>

      <div class="search-btn" @click="getTableData()" v-if="Btn.search">
        <div class="btn-img"></div>查询
      </div>
      <div class="add-btn" @click="handleClick(null, 'add')" v-if="Btn.add"
        v-show="btnPermissionSearch('basicData', 'fileManage', 'add')">
        <div class="btn-img"></div>新增
      </div>
      <div class="export-btn" @click="handleClick(null, 'export')" v-if="Btn.export" v-loading="exportLoading">
        <div class="btn-img"></div>
        {{ !exportLoading ? "导出" : "导出中" }}
      </div>
      <div class="deletes-btn" @click="handleClick(null, 'deletes')" v-if="Btn.deletes"
        v-show="btnPermissionSearch('basicData', 'fileManage', 'deletes')">
        批量删除
      </div>
    </div>
    <div class="base-table">
      <el-table highlight-current-row ref="myTable" :data="tableAllData" @selection-change="handleSelectionChange"
        height="100%" :span-method="objectSpanMethod" show-summary :summary-method="getSummaries">
        <myTableColumn :data="tableItems"></myTableColumn>
      </el-table>
    </div>
  </div>
</template>
<script>
const myTableColumn = {
  functional: true,
  props: ['data'],
  render(h, { props }) {
    function createNode(list) {
      return list.map((v) => {
        if (v.children && v.children.length > 0) {
          return (
            <el-table-column prop={v.prop} label={v.name} key={v.prop}
              header-align={v.align ?? 'right'} align={v.align ?? 'right'}>
              {createNode(v.children)}
            </el-table-column>
          );
        } else {
          return <el-table-column prop={v.prop} label={v.name} key={v.prop}
            header-align={v.align ?? 'right'} align={v.align ?? 'right'} fixed={v.fixed}
            sortable={v.sortable} ></el-table-column>
        }
      });
    }
    return createNode(props.data)
  },
};
import treeSelect from "@/components/common/treeSelect"
import { service } from "../../services/backServices"
import FileControl from '@/components/common/FileControl.vue';
import { export_json_to_excel } from "@/assets/js/FilExport";
import { saveAs } from "file-saver";
import dayjs from "dayjs";
export default {
  props: [
    "query",//查询参数
    "tableItems",//表格表头
    "updateItems",//增删查改的对象属性
    "methodParam",//方法参数
    "Btn",//自定义btn功能
    "menuName",//权限-菜单名称
    "pageName",//权限-页面名称
    "optionList",
  ],
  components: { treeSelect, FileControl, myTableColumn },
  data() {
    return {
      uploading: false,
      exportLoading: false,
      loading: false,
      method: {},
      multipleSelection: [],
      showWhich: "",
      updateInfo: {
        fileName: ''
      },
      params: {},
      cascaderSet: {
        value: 'value',
        emitPath: false,
        checkStrictly: false,
        expandTrigger: 'hover',
        multiple: false
      },
      addformRules: {
        fileName: [
          { required: true, message: '文件名称', trigger: 'blur' },
        ],
        fileAdd: [
          { required: true, message: '上传文件', trigger: 'blur' },
        ],
        uploadType: [
          { required: true, message: '上传类型', trigger: 'change' },
        ]
      },
      pickerOptions: {
        shortcuts: [
          {
            text: "最近一天",
            onClick(picker) {
              const end = new Date();
              const start = new Date();
              start.setTime(start.getTime() - 3600 * 1000 * 24 * 1);
              picker.$emit("pick", [start, end]);
            },
          },
          {
            text: "最近两天",
            onClick(picker) {
              const end = new Date();
              const start = new Date();
              start.setTime(start.getTime() - 3600 * 1000 * 24 * 2);
              picker.$emit("pick", [start, end]);
            },
          },
          {
            text: "最近三天",
            onClick(picker) {
              const end = new Date();
              const start = new Date();
              start.setTime(start.getTime() - 3600 * 1000 * 24 * 3);
              picker.$emit("pick", [start, end]);
            },
          }
        ],
        disabledDate: (time) => {
          return time.getTime() > Date.now() - 8.64e7;
        },
      },
      pickerOptionsMonth: {
        shortcuts: [{
          text: '本月',
          onClick(picker) {
            picker.$emit('pick', [new Date(), new Date()]);
          }
        }, {
          text: '今年至今',
          onClick(picker) {
            const end = new Date();
            const start = new Date(new Date().getFullYear(), 0);
            picker.$emit('pick', [start, end]);
          }
        }, {
          text: '最近六个月',
          onClick(picker) {
            const end = new Date();
            const start = new Date();
            start.setMonth(start.getMonth() - 6);
            picker.$emit('pick', [start, end]);
          }
        }]
      },
      dialogTitle: {
        add: "新增",
        edit: "编辑",
        detail: "详情"
      },
      showDialog: false,
      tableAllData: [],
      combineHash: {},
    };
  },
  computed: {
    queryInput() {
      let list = this.query.filter(v => {
        return v.type == "input"
      });
      return list;
    },
    querySelect() {
      let list = this.query.filter(v => {
        return v.type == "select"
      });
      return list;
    },
    queryCascader() {
      let list = this.query.filter(v => {
        return v.type == "cascader"
      });
      return list;
    },
    queryTime() {
      let list = this.query.filter(v => {
        return v.type == "time"
      });
      return list;
    },
    queryMonth() {
      let list = this.query.filter(v => {
        return v.type == "month"
      });
      return list;
    },
    ImportAPI() {
      return GlobalSetting.IotConfig.ftpAPIService;
    },
  },
  created() {
    let _this = this;
    function getParam(query) {
      let myForm = new FormData()
      Object.keys(query).forEach((key) => {
        if (Array.isArray(query[key]) && key.search(/[Tt]ime/) !== -1) {
          myForm.append('beginDate', query[key].length ? query[key][0] : '')
          myForm.append('endDate', query[key].length ? query[key][1] : '')
        } else if (query[key] !== "") {
          myForm.append(key, query[key])
        }
      })

      return myForm
    };
    _this.method.getData = async function (query) {
      let url = _this.methodParam;
      return service({
        url: url,
        method: "post",
        data: getParam(query)
      });
    };
    _this.method.addData = async function (model) {
      return service({
        headers: {
          'Content-Type': 'application/json'
        },
        method: 'post',
        url: _this.methodParam + "/save",
        data: model,
      });
    };
    _this.method.editData = async function editTrashOverflowData(model) {
      return service({
        headers: {
          'Content-Type': 'application/json'
        },
        method: 'post',
        url: _this.methodParam + "/update",
        data: model,
      });
    };
    _this.method.deleteDatas = async function (ids) {
      return service({
        method: 'post',
        url: _this.methodParam + "/batchRemove",
        params: {
          ids: ids
        },
        paramsSerializer: params => {
          return qs.stringify(params, {
            indices: false
          })
        }
      });
    };
    _this.method.uploadData = async function (data) {
      return service({
        headers: {
          'Content-Type': 'multipart/form-data; boundary=----WebKitFormBoundaryqs8javp5GsOgKvoQ'
        },
        method: 'post',
        url: _this.methodParam + "/upload",
        data: data,
        params: {
          uploadType: _this.updateInfo.uploadType
        }
      });
    };
    _this.method.downloadMethod = async function (url) {
      return service({
        method: 'post',
        url: _this.methodParam + "/download",
        responseType: 'blob',
        data: {
          url: url
        },
      });
    };
  },
  mounted() {
    this.getTableData();
  },
  methods: {
    getSummaries({ columns, data }) {
      const sums = [];
      columns.forEach((column, index) => {
        if (index === 0) {
          sums[index] = '总计';
          return;
        }
        const values = data.map(item => Number(item[column.property]));
        if (!values.every(value => isNaN(value)) && column.label.includes("销售")) {
          sums[index] = values.reduce((prev, curr) => {
            const value = Number(curr);
            if (!isNaN(value)) {
              return prev + curr;
            } else {
              return prev;
            }
          }, 0).toFixed(2);
          // sums[index] += ' 元';
        } else {
          sums[index] = '--';
        }
      });
      return sums;
    },
    objectSpanMethod({ row, column, rowIndex, columnIndex }) {
      if (this.combineHash[columnIndex]) {
        let index = 0;
        while (this.combineHash[columnIndex].rule[index] < rowIndex) {
          index++
        }
        let min = this.combineHash[columnIndex].rule[index]
        let max = this.combineHash[columnIndex].rule[index + 1] ?? this.tableAllData.length
        if (this.combineHash[columnIndex].rule[index] == rowIndex) {
          // 如果最后一项独立成行需要特殊处理
          let len = max - min
          return {
            rowspan: len,
            colspan: 1
          };
        } else {
          return {
            rowspan: 0,
            colspan: 0
          };
        }
      }
    },
    getTableData() {
      this.loading = true
      this.query.forEach(v => {
        this.params[v.prop] = v.value
      })
      for (let i = 0; i < 3; i++) {
        if (!this.tableItems[i].children) {
          this.combineHash[i] = {
            prop: this.tableItems[i].prop,
            column: i,
            rule: [0], //合并规则
          }
        }
      }
      this.method.getData(this.params).then(response => {
        this.loading = false
        if (response.data.code == 200) {
          this.tableAllData = response.data.data;
          this.$nextTick(() => {
            this.$refs.myTable.doLayout();
          });
          // 设置合并列
          for (let i = 1; i < this.tableAllData.length; i++) {
            for (let key in this.combineHash) {
              let prop = this.combineHash[key].prop
              if (this.tableAllData[i][prop] != this.tableAllData[i - 1][prop]) {
                this.combineHash[key].rule.push(i)
              }
            }
          }
        }
      })
    },
    handleSelectionChange(val) {
      this.multipleSelection = [];
      val.forEach(v => {
        this.multipleSelection.push(v.id);
      })
    },
    getFileName(val) {
      let title = ''
      if (val && val.length > 0) {
        for (let i = 0; i < val.length - 1; i++) {
          title += val[i]
        }
      } else {
        title = ''
      }
      this.updateInfo.fileName = title
      this.$forceUpdate();
    },
    // 增删改查
    handleClick(row, obj) {
      if (this.uploading) {
        this.$message({
          message: '存在正在上传的文件，请等待数据上传成功再试',
          type: 'warning'
        });
        return
      }
      switch (obj) {
        case "add":
          this.updateInfo = {};
          this.showWhich = obj;
          this.showDialog = true
          this.$nextTick(() => {
            this.$refs.addformRef.clearValidate();
          })
          break;
        case "edit":
          this.updateInfo = JSON.parse(JSON.stringify(row));
          this.showWhich = obj;
          this.showDialog = true
          this.$nextTick(() => {
            this.$refs.addformRef.clearValidate();
          })
          break;
        case "detail":
          this.updateInfo = JSON.parse(JSON.stringify(row));
          this.showWhich = obj;
          this.showDialog = true
          break;
        case "export":
          this.exportTable();
          break;
        default:
          break;
      }
    },
    handleSubmitFile() {
      if (!this.updateInfo.uploadType && this.updateInfo.uploadType != 0) {
        this.$message({
          message: '上传类型不能为空',
          type: 'warning'
        });
        return
      }
      this.handleSubmit();
    },
    //提交事件
    async handleSubmit() {
      let _this = this;
      const fileDom = this.$refs.myFileControl
      if (fileDom && fileDom[0]) {
        this.uploading = true
        let fileList = await fileDom[0].uploadInfo(), propName = 'file'
        this.uploading = false
        if (!!fileList) {
          _this.updateInfo[propName + 'AddStr'] = JSON.stringify(fileList);   //去掉最后一个逗号避免后端报错，再加上中括号构造json字符串          
          _this.updateInfo['fileName'] = fileList[0].name;    //从上传的文件中读取文件名
        }
        if (fileDom[0]?.delFileList?.length > 0) {       // 将删除的图片由数组转为字符串拼接
          _this.updateInfo[propName + 'DelStr'] = JSON.stringify(fileDom[0].delFileList)
        }
      }
      if (!_this.updateInfo.fileName) {
        this.$message({
          message: '文件不能为空',
          type: 'warning'
        });
        return
      }
      switch (this.showWhich) {
        case 'add':
          this.addInfo();
          break;
        case 'edit':
          this.editInfo();
          break;
      }
    },
    addInfo() {
      let _this = this;
      this.method.addData(_this.updateInfo).then(function (response) {
        if (response.data.code == 0) {
          _this.getTableData();
          _this.showWhich = "";
          _this.showDialog = false
          _this.$notify({
            message: "信息保存成功！",
            type: "success",
            position: "bottom-right",
            duration: 2000,
          });
        }
      }).catch(function (error) {
        _this.$notify({
          message: "信息保存失败！",
          type: "error",
          position: "bottom-right",
          duration: 2000,
        });
      });
    },
    editInfo() {
      let _this = this;
      this.method.editData(_this.updateInfo).then(function (response) {
        if (response.data.code == 0) {
          _this.getTableData();
          _this.showWhich = "";
          _this.showDialog = false
          _this.$notify({
            message: "信息保存成功！",
            type: "success",
            position: "bottom-right",
            duration: 2000,
          });
        }
      }).catch(function (error) {
        _this.$notify({
          message: "信息保存失败！",
          type: "error",
          position: "bottom-right",
          duration: 2000,
        });
      });
    },
    closeDialog() {
      this.showDialog = false
    },
    exportTable() {
      this.exportLoading = true;
      function getParam(query) {
        let myForm = new FormData()
        Object.keys(query).forEach((key) => {
          if (Array.isArray(query[key]) && key.search(/[Tt]ime/) !== -1) {
            myForm.append('beginDate', query[key].length ? query[key][0] : '')
            myForm.append('endDate', query[key].length ? query[key][1] : '')
          } else if (query[key] !== "") {
            myForm.append(key, query[key])
          }
        })
        return myForm
      };
      service({
        url: "pinxiangExport",
        method: "post",
        responseType: 'blob', // 设置返回格式为blob
        data: getParam(this.params)
      }).then(res => {
        this.exportLoading = false;
        let filename = "" + dayjs().format("YYYY-MM-DD HH:ss:mm");
        saveAs(res.data, filename + ".xlsx");
      }).catch(() => {
        this.exportLoading = false;
      })
    },
  },

  activated() {
    let _this = this;
    _this.$nextTick(() => {
      _this.$refs.myTable.doLayout();
    })
  }
}
</script>
<style scoped>
.base-table {
  bottom: 20px;
}
</style>